/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.uoc.tdp.servidor.bbdd.proves;

import edu.uoc.tdp.bbdd.GestorDiscConnexio;
import edu.uoc.tdp.beans.conexio.Estudiant;
import edu.uoc.tdp.beans.estudiants.Participacio;
import edu.uoc.tdp.beans.proves.PreguntaResposta;
import edu.uoc.tdp.beans.proves.Prova;
import edu.uoc.tdp.beans.proves.Ronda;

import edu.uoc.tdp.common.EOlympicsException;
import edu.uoc.tdp.common.EOlympicsExceptionProva;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * Classe gestora de les participacions de les provs
 * @author GRUP TDP 1X4j
 */
public class GestorParticipacio {

    private GestorDiscConnexio gestor;
    private Connection connexio;

    /**
     * Constructor de la classe Gestora
     * Crea un nou gestor de disc.
     */
    public GestorParticipacio() throws EOlympicsException {
        this.gestor = new GestorDiscConnexio();
        this.gestor.obreConnexioBD();
        this.connexio = gestor.getConnexio();
    }

    /**
     * Constructor de la classe Gestora
     * Utilitza el gestor de disc passat com a paràmetre
     * @param gdc connexió a la BD de tipus GestorDiscConnexio
     */
    public GestorParticipacio(GestorDiscConnexio gdc) {
        this.gestor   = gdc;
        this.connexio = gdc.getConnexio();
    }
    
    /**
     * Calcula i anota la nota d'una ronda 
     * @param prova                         Prova a computar
     * @param tipusRonda                    Tipus de ronda a computar
     * @throws EOlympicsException
     * @throws EOlympicsExceptionProva 
     */
    public void calcularNotaRonda(Prova prova, String tipusRonda) throws EOlympicsException, EOlympicsExceptionProva{               
        GestorRonda gRonda=new GestorRonda(gestor);
        GestorProva gProva=new GestorProva(gestor);
        Ronda ronda;
                
        List <Participacio> participacions= new ArrayList<Participacio>();                
        List<PreguntaResposta> respostesEstudiant= new ArrayList<PreguntaResposta>();
        
        try {
            gestor.getConnexio().setAutoCommit(false);        
            
            participacions=GetParticipacioClassificats(prova.getIdProva(),tipusRonda);     //agafo les participacions    
            
            tancarProva(prova);
            if(tipusRonda.equals("E") ){ //afago ronda
                    ronda=gRonda.getRondaEliminatoria(prova.getIdProva()); 
                    
            }else{                     
                    ronda=gRonda.getRondaFinal(prova.getIdProva());
            }

            for(Participacio part:participacions){ //recorro els estudiants
                respostesEstudiant =getRespostesEstudiant(part.getEstudiant().getIdIntern(),part.getProva().getIdProva(),tipusRonda);             
                part.setRespostesEncertades(ronda.getRespostesCorrectes(respostesEstudiant));
                part.setRespostesFallades(ronda.getRespostesIncorrectes(respostesEstudiant));
                part.setRespostesBlanc(ronda.getNombrePreguntes()-part.getRespostesEncertades()-part.getRespostesFallades());
                part.setNota(ronda.getNotaRonda(respostesEstudiant));
               // participacions.add(part);                        
            }
            
            setInscriureParticipacio(participacions);
            
            
            participacions=GetParticipacioClassificats(prova.getIdProva(),tipusRonda);
            
            setInserirGuanyadorRonda(participacions);
            gestor.getConnexio().commit();
        } catch (SQLException ex) {
            try {
                gestor.getConnexio().rollback();
                treatExceptionSQL(ex.getMessage());
            } catch (SQLException ex1) {
                treatExceptionSQL(ex1.getMessage());
            }
        }
        
    }
    /**
     * Obté les respostes d'un estudiant
     * @param idEstudiant           Identificador de l'estudiant
     * @param idProva               Identificador de la prova
     * @param tipusRonda            Tipus de ronda
     * @return  Llista de preguntaResposta de l'estudiant
     * @throws EOlympicsException 
     */
    private List<PreguntaResposta>getRespostesEstudiant (Integer idEstudiant,Integer idProva, String tipusRonda ) throws EOlympicsException{
        Statement st=gestor.creaSentencia();
        List <PreguntaResposta> respostesEstudiant = new ArrayList <PreguntaResposta>();
        String sql= "SELECT numPregunta,opcioMarcada FROM RESPOSTAESTUDIANT "
                + "WHERE idProva="+ idProva 
                +" AND tipusRonda ='"+ tipusRonda +"' "
                + "AND idEstudiant="+ idEstudiant ;
       ResultSet rs=null;
        try{
           rs=st.executeQuery(sql);
           while (rs.next()){
               if(!("").equals(rs.getString(2))){
                   respostesEstudiant.add(new PreguntaResposta(rs.getInt(1),rs.getString(2)));
               }
               
           }
           rs.close();
           st.close();
       }catch(SQLException sqle){
            try {
                gestor.getConnexio().rollback();
                if(!st.isClosed())st.close();
                if (!rs.isClosed()) rs.close();
                
            } catch (SQLException ex) {
                throw new EOlympicsException(EOlympicsException.ERR_SQL);
            }
           throw new EOlympicsException(EOlympicsException.ERR_SQL);
       }
        return respostesEstudiant;
    }
    /**
     * Obté la participació d'una ronda
     * @param idProva               Identificador de la prova
     * @param tipusRonda            Tipus de ronda
     * @return  Llista participació
     * @throws EOlympicsException 
     */
    private List<Participacio> GetParticipacio(Integer idProva, String tipusRonda) throws EOlympicsException{
        List<Participacio> participacions=new ArrayList<Participacio>();
        Estudiant estudiant;
        Participacio participacio;
        Prova prova =new Prova();
        prova.setIdProva(idProva);
        Statement st=gestor.creaSentencia();        
        String sql= "SELECT idEstudiant FROM PARTICIPACIO "
                + "WHERE idProva="+ idProva 
                + " AND tipusRonda='"+tipusRonda+"' "
                + "order by nota desc, dataParticipacio";
                
       ResultSet rs=null;
        try{
         
           rs=st.executeQuery(sql);
           while (rs.next()){
               estudiant = new Estudiant(); 
               participacio=new Participacio();               
               estudiant.setIdIntern(rs.getInt(1));
               participacio.setProva(prova);
               participacio.setEstudiant(estudiant);
               participacio.setTipusRonda(tipusRonda);
               participacions.add(participacio);
           }
           rs.close();
           st.close();
       }catch(SQLException sqle){
            try {
                gestor.getConnexio().rollback();
                if(!st.isClosed())st.close();
                if (!rs.isClosed()) rs.close();                
            } catch (SQLException ex) {
                throw new EOlympicsException(EOlympicsException.ERR_SQL);
            }
           
            throw new EOlympicsException(EOlympicsException.ERR_SQL);
       }
        return participacions;        
    }
    
    /**
     * Obté les participacions dels 10 primers classificats en na prova
     * @param idProva               Indentificador prova
     * @param tipusRonda            Tipus de ronda
     * @return  Llista de participacions
     * @throws EOlympicsException 
     */
    private List<Participacio> GetParticipacioClassificats(Integer idProva, String tipusRonda) throws EOlympicsException{
        List<Participacio> participacions=new ArrayList<Participacio>();
        Estudiant estudiant;
        Participacio participacio;
        Prova prova =new Prova();
        prova.setIdProva(idProva);
        Statement st=gestor.creaSentencia();        
        String sql= "SELECT idEstudiant FROM PARTICIPACIO P "
                + "WHERE idProva="+ idProva 
                + " AND tipusRonda='"+tipusRonda+"' "
                + "AND (Select count(*) From respostaEstudiant where idprova="+idProva+ " AND tipusRonda='"+tipusRonda+ "' "
                + "AND idEstudiant = P.idEstudiant)>0 "
                + "order by nota desc, dataParticipacio";
                
       ResultSet rs=null;
        try{
         
           rs=st.executeQuery(sql);
           while (rs.next()){
               estudiant = new Estudiant(); 
               participacio=new Participacio();               
               estudiant.setIdIntern(rs.getInt(1));
               participacio.setProva(prova);
               participacio.setEstudiant(estudiant);
               participacio.setTipusRonda(tipusRonda);
               participacions.add(participacio);
           }
           rs.close();
           st.close();
       }catch(SQLException sqle){
            try {
                gestor.getConnexio().rollback();
                if(!st.isClosed())st.close();
                if (!rs.isClosed()) rs.close();                
            } catch (SQLException ex) {
                throw new EOlympicsException(EOlympicsException.ERR_SQL);
            }
           
            throw new EOlympicsException(EOlympicsException.ERR_SQL);
       }
        return participacions;        
    }
    
    /**
     * Inscriu la participacio d'una prova
     * @param participacions        Llista de participacions a inscriure
     * @throws EOlympicsException 
     */
    private void setInscriureParticipacio(List<Participacio> participacions) throws EOlympicsException{
        
        String sql = "UPDATE PARTICIPACIO SET respostesEncertades=?,respostesFallades=?,respostesBlanc=?,nota=? "
                + "WHERE idProva=? AND tipusRonda=? AND idEstudiant=?"; 
        PreparedStatement ps=null;         
        try{
            ps=gestor.crearPreparedStatement(sql);
            for(Participacio pre:participacions){                
                ps.setInt(1, pre.getRespostesEncertades());
                ps.setInt(2, pre.getRespostesFallades());
                ps.setInt(3, pre.getRespostesBlanc());
                ps.setFloat(4, pre.getNota());                
                ps.setInt(5, pre.getProva().getIdProva());
                ps.setString(6, pre.getTipusRonda());
                ps.setInt(7, pre.getEstudiant().getIdIntern());                               
                ps.executeUpdate();
            }
            ps.close();
        }catch (SQLException sqle){
            try {
                gestor.getConnexio().rollback();
                ps.close();
                treatExceptionSQL(sqle.getMessage());     
            } catch (SQLException ex) {
                treatExceptionSQL(ex.getMessage());     
            }           
        }
        
    }
    
    
    /**
     * Guarda la classificació d'una ronda
     * @param participacions            Llistat de partipacions
     * @throws EOlympicsException
     * @throws EOlympicsExceptionProva 
     */
    private void setInserirGuanyadorRonda(List<Participacio> participacions) throws EOlympicsException, EOlympicsExceptionProva{
        
        Integer tempPos=0;
        String sql = "INSERT INTO GUANYADORRONDA (idProva, tipusRonda,idEstudiant,posicioOcupada) "                        
                    + "VALUES (?,?,?,?)";
        PreparedStatement ps=null;         

        tempPos=1;
        try{
            ps=gestor.crearPreparedStatement(sql);
            for(Participacio pre:participacions){
                ps.setInt(1, pre.getProva().getIdProva());
                ps.setString(2, pre.getTipusRonda());
                ps.setInt(3, pre.getEstudiant().getIdIntern());
                ps.setInt(4,tempPos );
                ps.executeUpdate();
                tempPos++;
            }
            ps.close();
        }catch (SQLException sqle){
            try {
                
                gestor.getConnexio().rollback();
                ps.close();
                treatExceptionSQL(sqle.getMessage());     
            } catch (SQLException ex) {
                treatExceptionSQL(ex.getMessage());     
            }

        }
        
        
    }
    /**
     * Tanca la partipació d'una prova
     * @param prova                 Prova a tancar
     * @throws EOlympicsException
     * @throws EOlympicsExceptionProva
     * @throws SQLException 
     */
    private void tancarProva(Prova prova) throws EOlympicsException,EOlympicsExceptionProva, SQLException{
        Statement st=gestor.creaSentencia();
        String sql="UPDATE PROVA SET estat='"+prova.getEstat()+"',usuariMod="+prova.getUsuariModificacio().getIdIntern() +", "
                + "dataMod='"+ new java.sql.Date(System.currentTimeMillis()) +"' "          
                + "WHERE idProva ="+ prova.getIdProva() ;            
            st.executeUpdate(sql);            
            st.close();
        
        
    }
    /**
     * Control d'excepcions que es poden donar en una participació
     * @param sqle
     * @throws EOlympicsExceptionProva
     * @throws EOlympicsException 
     */
    private void treatExceptionSQL(String sqle) throws EOlympicsExceptionProva, EOlympicsException{
                       
            if(sqle.contains("pk_participacio")) {
               throw new EOlympicsExceptionProva(EOlympicsExceptionProva.ERR_SQL_PK_PARTICIPACIO);
           }else if(sqle.contains("fk_inscripcio_part")) {
               throw new EOlympicsExceptionProva(EOlympicsExceptionProva.ERR_SQL_FK_INSCRIPCIO);           
           }else if(sqle.contains("fk_ronda_part")) {
               throw new EOlympicsExceptionProva(EOlympicsExceptionProva.ERR_SQL_FK_RONDA);           
           }else if(sqle.contains("pk_guanyadorronda")) {
               throw new EOlympicsExceptionProva(EOlympicsExceptionProva.ERR_SQL_PK_GUANYADORRONDA);               
           }else if(sqle.contains("fk_ronda_gr")) {
               throw new EOlympicsExceptionProva(EOlympicsExceptionProva.ERR_SQL_FK_RONDA_GR);           
           }else if(sqle.contains("fk_estudiant_gr")) {
               throw new EOlympicsExceptionProva(EOlympicsExceptionProva.ERR_SQL_FK_ESTUDIANT_GR);           
           }
           else{
             throw new EOlympicsException(EOlympicsException.ERR_SQL);
            
         }
           
    }

}
